package feie

import (
	"strings"
	"unicode"
)

type Printer string

type composingTemp struct {
	S []string
	L int
}

// 排版
func (r *Printer) Composing(symbol ...PrintSymbol) []string {
	cs := make([]*composingTemp, 0)
	mi := 0
	rs := make([]string, 0)
	for _, p := range symbol {
		out := p.Out(p.ComposingWidth)
		l := len(out)
		if l > mi {
			mi = l
		}
		temp := composingTemp{
			S: out,
			L: l,
		}
		cs = append(cs, &temp)
	}
	bd := strings.Builder{}
	for i := 0; i < mi; i++ {
		for _, c := range cs {
			if i > c.L-1 {
				continue
			}
			bd.WriteString(c.S[i])
		}
		bd.WriteString("<BR>")
		rs = append(rs, bd.String())
		bd.Reset()
	}
	return rs
}

func (r *Printer) Exe(times int, ps [][]PrintSymbol) error {
	bd := strings.Builder{}
	for _, ss := range ps {
		com := r.Composing(ss...)
		for _, c := range com {
			bd.WriteString(c)
		}
	}
	return Print(bd.String(), string(*r), times)
}

type PrintSymbol struct {
	// 打印内容
	Content string
	// 排版宽度
	ComposingWidth int
	Tag            string
}

// 所占宽度
func (r *PrintSymbol) Width() int {
	ln := 0
	for _, s := range r.Content {
		if unicode.Is(unicode.Han, s) {
			ln += 2
		} else if unicode.IsPunct(s) && s > 65280 && s < 65381 {
			ln += 2
		} else {
			ln++
		}
	}
	return ln
}

// 输出打印内容 限制宽度
func (r *PrintSymbol) Out(lw int) []string {
	if lw == 0 {
		s := r.Content
		if r.Tag != "" {
			s = "<" + r.Tag + ">" + s + "</" + r.Tag + ">"
		}
		return []string{s}
	}
	width := r.Width()
	bd := strings.Builder{}
	if width <= lw {
		r.fillSpace(&bd, lw, width)
		s := r.Content + bd.String()
		if r.Tag != "" {
			s = "<" + r.Tag + ">" + s + "</" + r.Tag + ">"
		}
		return []string{s}
	}
	cn := 0
	ss := make([]string, 0)
	for _, s := range r.Content {
		ci := 1
		if unicode.Is(unicode.Han, s) {
			ci = 2
		} else if unicode.IsPunct(s) && s > 65280 && s < 65381 {
			ci = 2
		}
		cn += ci
		if cn <= lw {
			_, _ = bd.WriteRune(s)
		} else {
			r.fillSpace(&bd, lw, cn-ci)
			if r.Tag != "" {
				ss = append(ss, "<"+r.Tag+">"+bd.String()+
					"</"+r.Tag+">")
			} else {
				ss = append(ss, bd.String())
			}
			bd.Reset()
			_, _ = bd.WriteRune(s)
			cn = ci
		}
	}
	ln := bd.Len()
	if ln != 0 {
		r.fillSpace(&bd, lw, ln)
		if r.Tag != "" {
			ss = append(ss, "<"+r.Tag+">"+bd.String()+
				"</"+r.Tag+">")
		} else {
			ss = append(ss, bd.String())
		}
	}
	return ss
}

func (r *PrintSymbol) fillSpace(bd *strings.Builder, lw, ln int) {
	for i := 0; i < lw-ln; i++ {
		bd.WriteString(" ")
	}
}
